Productize automatic execution cadence in Goal settings - #4933
Conversation
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
English verdict: REQUEST_CHANGES - head c350b60; local API, build and packaged UI checks passed, but the conflict-status classifier needs a typed source.
动机
把已有的 quota-owned 自动执行间隔策略放进 Goal 设置,让所有者能按 Goal / Agent / automation 范围检查、预览、保存和读回。此 PR 不声称能修改 Codex App 定时器,也不声称已具备启动模型前拦截。
改动思路
前端调用本地 chat 配置 API;Python 只校验请求和做回读,策略计算与持久化仍由 TypeScript 的 quota.automation_cadence.manage 负责。基线相同 loopback GET 返回 404;此 head 返回 200,预览不写入,执行后按修订号及来源回读。
具体改动
- 设置页新增作用域、直接/继承下限、所有者原因、降额确认与预览-应用交互;界面明确“排程建议,App hook 尚未验证”。打包桌面/移动端场景通过。
- 真实 loopback→TS store 测试通过(1 项),覆盖预览、应用、继承、旧修订拒绝和降额确认;打包构建/类型检查、Ruff、diff check 均通过。
- [P2,需修复]
loopx/chat_automation_cadence_api.py:223-231用异常文案是否包含revision conflict或stale来决定 409 和automation_cadence_conflict。TS 当前对修订冲突复用通用automation_cadence_invalid拒绝码,因此文案一变,冲突就会被误报为 400/invalid request。最小反例:给处理器一个EffectRuntimeConflict("policy advanced", diagnostic_code="configuration_revision_conflict"),实测得到 400。请在 TS owner 发出独立的类型/诊断码,Python 按类型/码映射,并用不含现有关键词的冲突文案加回归。不要把错误文本当状态机。
对主干的风险
上述误分类会破坏调用者区分“刷新后重试”和“输入错误”的稳定 API 语义。App 定时触发到 pre-model hook 的资格仍未证明,PR 的边界文案对此诚实;浏览器场景 mock HTTP,但真实 loopback 测试覆盖策略写入。未按本 Goal 的 wait_for_ci=false 配置轮询远端 CI。
我的整体评价
方向和模块归属正确,交互/回读切片可独立验证;请先修 typed conflict 及负例,再在新 head 重跑 exact-head review。此变更涉及运行时与前端,按仓库规则由维护者合并。
…ge text The loopback settings API decided 409/automation_cadence_conflict by looking for 'revision conflict' or 'stale' inside the error text, while the quota owner raised a generic request_rejected for a stale expected_revision. Rewording that message would silently turn a refresh-and-retry conflict into a 400 invalid request. The owner now raises EffectRuntimeConflictError with the stable diagnostic code automation_cadence_revision_conflict, and the API maps failures by type: typed conflicts (including a superseded preview digest) stay 409, rejected input stays 400. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
The prior regression passed only because the conflict message contained the keyword the API matched. The new case raises a typed conflict whose text carries no legacy keyword, and the end-to-end loopback test asserts a superseded preview digest is still 409 with the conflict error code. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Take main's generated chat bundle as the provisional side of a rename/rename conflict and keep both RFC narratives: main's two-phase managed-start recovery text plus this branch's M3 settings companion. The bundle is rebuilt from the merged sources in the following commit. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
The chat bundle conflicted as a rename/rename of generated assets. Rebuilding with vite.config.chat.config.ts from the merged dashboard sources restores a bundle that carries this branch's cadence settings page, keeps the bounded two-generation retention manifest, and prunes the superseded assets. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机
上一轮评审在 c350b60b64689438ddf51b3ac40e5e929d7b9093 上请求修改:设置页 loopback API 用异常文案是否包含 revision conflict 或 stale 来决定 409/automation_cadence_conflict,而 quota owner 对过期 expected_revision 抛出的却是通用 request_rejected。这意味着只要 TS 侧改写文案,调用者就会把"刷新后重试"的冲突误判为"输入非法",语义由字符串决定而不是由类型决定。
本 head bbc3fd4de0b3b0d9e00e64d5434722936e68604e 修复了该点。PR 本身的目标是把已有的 quota-owned 自动执行间隔策略产品化到 Goal 设置(M3 设置页阶段成果),让所有者按 Goal/Agent/automation 作用域检查、预览、保存并读回,同时不声称修改 Codex App 定时器或已具备启动前拦截。
改动思路
策略权威不变:TypeScript 的 quota.automation_cadence.manage 负责策略校验与持久化,Python 只做请求校验和回读,前端通过本地 chat 配置 API 访问,并用预览摘要(preview_revision)锁定"我预览的就是我要应用的修订号"。
本次修复把这条边界上的失败分类改成类型驱动:owner 在 expected_revision 与持久修订不一致时抛出带稳定诊断码的 typed conflict(automation_cadence_revision_conflict);Python 按异常类型映射——typed conflict(含被取代的预览摘要)→ 409 + automation_cadence_conflict,被拒绝的输入 → 400 + invalid_automation_cadence_request。错误文案不再参与状态判定,改写文案不会改变 API 契约。
具体改动
本 head 相对上一轮的改动集中在后端分类与回归:loopx/chat_automation_cadence_api.py 新增 SupersededCadencePreview 与 _cadence_failure_status(按类型映射状态与错误码);loopx/control_plane/quota/automation_cadence.ts 新增 typed conflict 抛出口并用于修订冲突;tests/test_chat_automation_cadence_api.py 增加"文案不含旧关键词仍为 409"的回归并断言过期预览摘要为 409;tests/control_plane_ts/automation_cadence.test.ts 断言冲突的 kind/code。PR 其余部分(设置页交互、i18n、样式、chat 数据访问、重打包的 chat bundle、两份 RFC)保持不变。
本 head 同时合入最新 main:冲突集中在生成的 chat bundle(rename/rename)与 RFC 附录叙述,解决方式是采用 main 的一代产物作为过渡、保留双方 RFC 叙述(main 的两阶段启动恢复 + 本 PR 的 M3 设置页成果),随后用 vite.config.chat.config.ts 从合并后的源码重新构建 bundle。
关键代码讲解
_cadence_failure_status与SupersededCadencePreview(loopx/chat_automation_cadence_api.py):把 HTTP 状态与错误码绑定到失败类型;预览摘要不再匹配提交字段时也走同一条 typed conflict 分支,保持原有 409 语义。conflict()与manageAutomationCadence的修订检查(loopx/control_plane/quota/automation_cadence.ts):过期配置意图现在以kind=conflict、code=automation_cadence_revision_conflict越界,而不是request_rejected。automation-cadence-settings.tsx(前端,本次未改):预览→应用→读回的交互仍依赖同一 API,因此分类修复直接改善"刷新后重试"的提示语义。- 重新生成的 chat bundle(
loopx/web/chat):经vite.config.chat.config.ts从合并源码构建,asset-retention.json仍限制在两代之内并清理了被取代的产物。 - 回归用例:
test_chat_cadence_conflict_status_ignores_message_wording在修复前会得到 400(已实测:assert 400 == 409),修复后为 409;端到端用例新增过期预览摘要 409 断言。
对主干的风险
最强反例就是上一轮给出的:把冲突文案改成不含旧关键词的措辞,旧实现立刻把冲突降级为 400,调用者据此放弃可恢复的重试。该反例现在有专门回归覆盖,并且在修复前的代码上确实失败,说明测试真的守住了这条语义。
边界与残留:App 定时触发到启动前 hook 的准入仍未验收,设置页只是候选成果而非推广;本次修复未改动前端交互,但合并后从源码重建了 chat bundle 并通过 dashboard-pwa-bundle-smoke.py 的 PWA 与资产保留契约;Lark/CLI 等待反馈一致性仍按 RFC 未完成项推进。
验证矩阵(本 head):Python chat 设置 API、Goal/machine 配置、automation cadence 与 Turn executor 共 95 用例通过;TS cadence 用例 7 项通过(含 typed kind/code 断言);npm run typecheck:control-plane、配置范围内 Ruff、python -m mypy(23 模块)、examples/docs-governance-smoke.py 与 examples/dashboard-pwa-bundle-smoke.py 通过;vite.config.chat.config.ts 重建 chat bundle 成功。本机未运行 Playwright 浏览器 smoke(需要浏览器依赖),merge 前的远端 CI 在该 PR 的上一 head 上 dashboard-acceptance、Windows/macOS desktop 与全部测试分片均通过;按本 Goal 的 wait_for_ci=false 与本轮维护者要求,未抓取或等待远端 CI。
语义与 CI 对齐
typed conflict 使用的是既有 effect-runtime 词汇(kind=conflict + 稳定诊断码),没有新增持久格式或公共字段;变化的只是设置 API 的失败分类来源。两份 RFC 追加了两阶段启动恢复与 M3 设置页边界,中英文同步。
我的整体评价
APPROVE:上一轮的唯一阻塞项已被实现为类型驱动的失败分类,并配有会在旧代码上失败、在新代码上通过的回归;设置页交互、回读与资产保留边界保持原样,chat bundle 从合并源码重建而非手改产物。范围仍与已复现问题相称,未引入新的 provider 或默认行为变更;剩余 App timer 路径与 Lark/CLI 等待一致性仍按 RFC 条件推进。
English verdict: APPROVE - exact head bbc3fd4de0b3b0d9e00e64d5434722936e68604e replaces message-text classification with typed conflict failures (stable diagnostic code, 409 preserved for superseded previews), rebases on latest main, and rebuilds the chat bundle from merged sources; 95 Python cases, 7 TypeScript cadence cases, typecheck, Ruff, mypy, docs governance and the PWA bundle smoke passed locally, and the new wording-independent regression fails on the pre-repair code.
|
Self-repair and merged decision record (admin-bypass merge, maintainer-authorized).
Repair content:
Validation at the merged head:
|
Problem and behavior
The quota-owned automatic-execution minimum interval from #4921 had no Goal settings editor, so an operator could not inspect inheritance or safely change a Goal, Agent, or automation floor from the product. Goal-specific settings also did not identify which Goal was being edited.
This adds an Automatic execution interval settings panel with effective-floor provenance, scoped preview, revision-checked apply, and readback. The shared settings heading now names the active Goal on Goal-specific tabs and clears that label on machine-wide tabs. The loopback API delegates policy decisions and writes to the existing quota owner; it does not create a second scheduler policy. The RFC checkpoint is updated to reflect the delivered UI and remaining host-admission work.
The panel explicitly states that this is a scheduler recommendation: it does not mutate existing Codex App automation schedules, and App timer-to-pre-model-hook admission remains unqualified. Managed Turn admission is tracked separately in #4929.
Validation
Future-facing boundary pass: reused the existing Goal settings navigation and quota authority, removed duplicate readback metrics, and left App hook work outside this PR.